package com.example.resturant.service.impl;

import com.example.resturant.exception.ServiceException;
import com.example.resturant.model.*;
import com.example.resturant.repository.*;
import com.example.resturant.service.AdminService;
import com.example.resturant.vo.*;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class AdminServiceImpl implements AdminService {

    @Resource
    private AdminRepository adminRepository;
    @Resource
    private OrderRepository orderRepository;
    @Resource
    private OrderMenuRepository orderMenuRepository;
    @Resource
    private MenuRepository menuRepository;
    @Resource
    private CommentRepository commentRepository;
    @Resource
    private AddressRepository addressRepository;
    @Resource
    private UserRepository userRepository;
    @Resource
    private NewsRepository newsRepository;

    @Override
    public void login(String username, String password) {
        Admin admin = adminRepository.findByUsername(username);
        if (admin == null) {
            throw new ServiceException("用户名或者密码错误");
        }
        if (ObjectUtils.notEqual(admin.getPassword(), password)) {
            throw new ServiceException("用户名或者密码错误");
        }
    }

    @Override
    public Page<OrderVO> listOrders(Pageable page) {
        Page<Order> orders = orderRepository.findAll(page);
        if (orders.isEmpty()) {
            return Page.empty(page);
        }
        List<Integer> orderIds = orders.stream().map(Order::getId).collect(Collectors.toList());
        List<OrderMenu> orderMenus = orderMenuRepository.findByOrderIdIn(orderIds);
        if (orderMenus.isEmpty()) {
            return Page.empty(page);
        }
        List<Comment> comments = commentRepository.findByOrderIdIn(orderIds);
        List<Integer> addressIds = orders.stream().map(Order::getAddressId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Address> addresses = addressRepository.findByIdIn(addressIds);
        Map<Integer, AddressVO> addressMap = addresses.stream().collect(Collectors.toMap(Address::getId, address -> {
            AddressVO addressVO = new AddressVO();
            BeanUtils.copyProperties(address, addressVO);
            return addressVO;
        }));
        Map<Integer, String> commentMap = comments.stream().collect(Collectors.toMap(Comment::getOrderId, Comment::getComment, (o, n) -> n));
        List<Integer> menuIds = orderMenus.stream().map(OrderMenu::getMenuId).collect(Collectors.toList());
        List<Menu> menus = menuRepository.findByIdIn(menuIds);
        Map<Integer, MenuVO> menuMap = menus.stream().collect(Collectors.toMap(Menu::getId, obj -> {
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(obj, menuVO);
            return menuVO;
        }, (o, n) -> n));
        Map<Integer, List<MenuVO>> orderMenuMap = orderMenus.stream()
                .collect(Collectors.groupingBy(OrderMenu::getOrderId, Collectors.mapping(orderMenu -> {
                    MenuVO menuVO = menuMap.get(orderMenu.getMenuId());
                    menuVO.setQuantity(orderMenu.getQuantity());
                    return menuVO;
                }, Collectors.toList())));
        return orders.map(order -> {
            OrderVO orderVO = new OrderVO();
            BeanUtils.copyProperties(order, orderVO);
            orderVO.setComment(commentMap.get(order.getId()));
            orderVO.setMenus(orderMenuMap.get(order.getId()));
            orderVO.setAddress(addressMap.get(order.getAddressId()));
            return orderVO;
        });
    }

    @Override
    public Page<UserVO> listUsers(Pageable page) {
        Page<User> users = userRepository.findAll(page);
        return users.map(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            return userVO;
        });
    }

    @Override
    public void updateUserState(Integer id) {
        User user = userRepository.getOne(id);
        user.setDeleted(BooleanUtils.negate(BooleanUtils.isTrue(user.getDeleted())));
        userRepository.save(user);
    }

    @Override
    public Page<MenuVO> listMenus(Pageable page) {
        Page<Menu> menus = menuRepository.findAll(page);
        return menus.map(menu -> {
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(menu, menuVO);
            return menuVO;
        });
    }

    @Override
    public void updateMenuState(Integer id) {
        Menu menu = menuRepository.getOne(id);
        menu.setDeleted(BooleanUtils.negate(BooleanUtils.isTrue(menu.getDeleted())));
        menuRepository.save(menu);
    }

    @Override
    public MenuVO upsertMenu(MenuVO req) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(req, menu);
        menu.setDeleted(false);
        menuRepository.save(menu);
        req.setId(menu.getId());
        return req;
    }

    @Override
    public Page<News> listNews(Pageable page) {
        return newsRepository.findAll(page);
    }

    @Override
    public void updateNewsState(Integer id) {
        News news = newsRepository.getOne(id);
        news.setDeleted(BooleanUtils.negate(BooleanUtils.isTrue(news.getDeleted())));
        newsRepository.save(news);
    }

    @Override
    public News upsertNews(News req) {
        req.setDeleted(false);
        newsRepository.save(req);
        return req;
    }
}
